//#include rfm

/**
 * NOTE: You must set the Facebook app ID to your application after the rfm.social.Facebook script is included, like so:
 * 
 *      rfm.social.Facebook.model.appId = "XXXXXXXX";
 *
 */

(function() {

if (!rfm.social) {
    rfm.social = {};
}

var _isLoaded = false,
	_scriptTimeoutId = null;

function _scrubQuery(query) {
	return query
		.replace('{{USERID}}', '"' + rfm.social.Facebook.model.userId + '"')
		.replace('{{APPID}}', '"' + rfm.social.Facebook.model.appId + '"');
}

/**
* Utility for working with the Facebook API
*/
rfm.social.Facebook = {
    /**
    * Data about the current application state
    */
    model: {
        /**
        * The Facebook application ID. This must be set externally in order to use the helper.
        */
        appId: null,
        /**
        * The user ID of the logged in Facebook user (or null if the user is not logged in or the helper has not been initialized)
        */
        userId: null,
        /**
        * The access token for the logged in Facebook user (or null if the user is not logged in or the helper has not been initialized) 
        */
        accessToken: null
    },
    /**
     * Find out whether or not the Facebook API is initialized
     * @returns {Boolean} True if the API is initialized
     */
    isLoaded: function() {
    	return _isLoaded;
    },
    /**
    * Loads the Facebook API
    * @param {Function} callback The function executed when the API has been loaded
    */
    init: function(callback) {
        if (!rfm.social.Facebook.model.appId) {
            throw 'You must set rfm.social.Facebook.model.appId to your application\'s ID';
        }
        else if (_isLoaded) {
            if (callback) {
                callback();
            }
        }
        else {
            if (_scriptTimeoutId === null) {
                var onload_fbScripts = function() {
                    if (_scriptTimeoutId) {
                        clearTimeout(_scriptTimeoutId);
                    }
                    _scriptTimeoutId = null;
                    if (window.FB) {
                        if (!_isLoaded) {
                            FB.init({
                                appId: rfm.social.Facebook.model.appId,
                                status: true,
                                cookie: true,
                                xfbml: true
                            });
                        }
                        _isLoaded = true;
                        if (callback) {
                            callback();
                        }
                    }
                    else {
                        _scriptTimeoutId = setTimeout(arguments.callee, 100);
                    }
                };
                (function() {
                    var e = document.createElement('script'),
                    fbRoot = document.getElementById('fb-root');
                    e.type = 'text/javascript';
                    e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
                    e.async = true;
                    if (!fbRoot) {
                        fbRoot = document.createElement('div');
                        fbRoot.setAttribute('id', 'fb-root');
                        document.body.appendChild(fbRoot);
                    }
                    fbRoot.appendChild(e);
                })();
                onload_fbScripts();
            }
            else {
                setTimeout(function() {
                    if (window.FB && _isLoaded) {
                        if (callback) {
                            callback();
                        }
                    }
                    else {
                        setTimeout(arguments.callee, 100);
                    }
                }, 0);
            }
        }
    },
    /**
    * Checks whether or not the user has granted a permission to this application
    * @param {Array} permissions A list of permission names to check
    * @param {Function} ongranted (Optional) A callback to execute when the application has permission
    * @param {Function} ondenied (Optional) A callback to execute when the application does not have permission
    */
	hasPermissions: function(permissions, ongranted, ondenied) {
		if (typeof permissions == 'string') {
			permissions = [permissions];
		}
		FB.ApiServer._readOnlyCalls = {};
        FB.api({
	            method: 'fql.query',
	            query: 'SELECT ' + permissions.join(', ') + ' FROM permissions WHERE uid=me()'
	        },
	        function(response) {
				if (!response || response.error) {
					if (ondenied) {
						ondenied(response);
					}
				}
				else {
					var hasPermissions = true;
					if (!response[0]) {
						hasPermissions = false;
					}
					else {
						for (var i = permissions.length - 1; i > -1; i--) {
							if ((response[0][permissions[i]] || 0).toString() !== '1') {
								hasPermissions = false;
								break;
							}
						}
					}
					if (hasPermissions) {
						if (ongranted) {
							ongranted(response);
						}
					}
					else if (ondenied) {
						ondenied(response);
					}
				}
	        });
	},
	/**
	* Event handler for when the user logs in
	*/
	onlogin: null,
    /**
    * Ensures that the user is logged in and has granted permissions to the application
    * @param {Array} permissions A list of permissions that the user has granted
    * @param {Function} onsuccess (Optional) A function to execute when the user has authenticated and granted permission
    * @param {Function} onerror (Optional) A callback executed when the operation fails or permission is denied
    */
    login: function(permissions, onsuccess, onerror) {
    	if (!permissions) {
            permissions = [];
        }
    	rfm.social.Facebook.init(function(response) {
            function onsuccess_login(response) {
				if (response.session) {
	            	var wasLoggedIn = null != rfm.social.Facebook.model.userId; 
	                rfm.social.Facebook.model.userId = response.session.uid;
	                rfm.social.Facebook.model.accessToken = response.session.access_token;
				}
                if (onsuccess) {
                    onsuccess(response);
                }
                if (!wasLoggedIn && rfm.social.Facebook.onlogin) {
                	rfm.social.Facebook.onlogin();
                }
            }
            function onunauthenticated() {
	        	FB.login(function(response) {
	        		if (response.session) {
	        			onsuccess_login(response);
	        		}
	        		else if (onerror) {
	        			onerror(response);
	        		}
	        	}, { perms: permissions ? permissions.join(',') : '' });
            }
            rfm.social.Facebook.checkLoginStatus(function(isLoggedIn) {
            	if (isLoggedIn) {
		            rfm.social.Facebook.hasPermissions(permissions || [], onsuccess_login, onunauthenticated);
            	}
            	else {
            		onunauthenticated();
            	}
            });
    	});
    },
    /**
    * Deauthenticates the user
    * @param {Function} callback (Optional) A function to execute when the user is successfully deauthenticated
    */
    logout: function(callback) {
        rfm.social.Facebook.model.userId = null;
        rfm.social.Facebook.model.authToken = null;
        FB.logout(callback);
    },
    /**
     * Check the user's authentication state
     * @param {Function} callback A callback to execute that will be passed a flag indicating whether or not the user is authenticated
     */
    checkLoginStatus: function(callback) {
    	FB.getLoginStatus(function(response) {
    		if (response.session) {
    			rfm.social.Facebook.model.userId = response.session.uid;
    			rfm.social.Facebook.model.accessToken = response.session.access_token;
    		}
    		if (callback) {
    		    callback(response.session !== null);
    		}
    	});
    },
    /**
    * Make a Facebook API call
    * @param {String} url The API URL
    * @param {String} type GET or POST
    * @param {Object} params The hash map to pass to the API
    * @param {Array} permissions Permissions required by the API call
    * @param {Function} onsuccess (Optional) A callback executed when the operation is successful
    * @param {Function} onerror (Optional) A callback executed when the operation fails or permission is denied
    */
    api: function(url, type, params, permissions, onsuccess, onerror) {
        rfm.social.Facebook.login(permissions, function() {
            FB.api(url, type, params,
		        function(response) {
		            if (response && !response.error) {
		                if (onsuccess) {
		                    onsuccess(response);
		                }
		            }
		            else {
		                if (onerror) {
		                    onerror(response);
		                }
		            }
		        });
        }, onerror);
    },
    /**
    * Utility functions for working with FQL
    */
    fql: {
        /**
        * Escapes a string value for inclusion in FQL
        * @param {String} str The string value
        */
        escape: function(str) {
            // TODO - how to escape quotes and other characters?
            return str;
        },
        /**
        * Makes a query to Facebook
        * @param {Array} permissions Permissions required to make the query
        * @param {String} fql The query to run
        * @param {Function} onsuccess (Optional) A callback to execute when the query is successfully completed
        * @param {Function} onerror (Optional) A callback executed when the operation fails or permission is denied
        * @param {Boolean} firstOnly (Optional) Whether or not to only return the first result
        */
        query: function(permissions, fql, onsuccess, onerror, firstOnly) {
            rfm.social.Facebook.login(permissions, function() {
        		FB.ApiServer._readOnlyCalls = {};
                FB.api({
                    method: 'fql.query',
                    query: _scrubQuery(fql)
                },
		        function(response) {
		            if (!response || response.error) {
		                if (onerror) {
		                    onerror(response);
		                }
		            }
		            else {
		                if (onsuccess) {
		                    onsuccess(firstOnly ? response[0] : response);
		                }
		            }
		        });
            }, onerror);
        },
        /**
        * Makes multiple queries to Facebook
        * @param {Array} permissions Permissions required to make the queries
        * @param {String} queries Set of queries to run
        * @param {Function} successHandlers (Optional) A set of callbacks to execute when the query is successfully completed
        * @param {Function} onsuccess (Optional) A callback executed when all success handlers have been called
        * @param {Function} onerror (Optional) A callback executed when the operation fails or permission is denied
        * @param {Boolean} firstOnly (Optional) Whether or not to only return the first result
        */
        multiquery: function(permissions, queries, successHandlers, onsuccess, onerror) {
            rfm.social.Facebook.login(permissions, function() {
            	for (var queryId in queries) {
            		queries[queryId] = _scrubQuery(queries[queryId]);
            	}
        		FB.ApiServer._readOnlyCalls = {};
                FB.api({
                    method: 'fql.multiquery',
                    queries: queries
                },
		        function(response) {
		            if (!response || response.error) {
		                if (onerror) {
		                    onerror(response);
		                }
		            }
		            else {
		                if (successHandlers) {
		                	for (var i = 0, j = response.length; i < j; i++) {
		                		var queryId = response[i].name,
		                			handler = successHandlers[queryId];
		                		if (handler) {
		                			handler(response[i].fql_result_set);
		                		}
		                	}
		                }
		                if (onsuccess) {
		                	onsuccess(response);
		                }
		            }
		        });
            }, onerror);
        }
    },
    /**
    * Functions for dealing with the user's feed
    */
    feed: {
        /**
        * Posts a link to the user's feed, using the standard Facebook dialog
        * @param {String} userMessage The user's comment about the linked page
        * @param {String} linkURL The absolute URL of the linked page
        * @param {String} linkName The name of the linked page
        * @param {String} linkDescription A description of the linked page
        * @param {String} linkThumbnailURL The absolute URL of a graphic for the linked page
        * @param {Function} onsuccess (Optional) A callback to execute when the post has been published
        * @param {Function} onerror (Optional) A callback to execute when the operation fails or permission is denied
        */
        postURLWithDialog: function(userPrompt, userMessage, linkURL, linkName, linkDescription, linkThumbnailURL, onsuccess, onerror) {
            var attachment = {
                name: linkName,
                description: linkDescription,
                href: linkURL
            };
            if (linkThumbnailURL) {
                attachment.media = [{ type: 'image', src: linkThumbnailURL, href: linkURL}];
            }
            FB.ui({
                method: 'stream.publish',
				mode: 'touch',
				display: 'popup',
                message: userMessage,
                attachment: attachment,
                user_message_prompt: userPrompt
            });
        }
    }
};

})();